<?php
/*********************************************
 *  CPG Dragonfly™ CMS
 *********************************************
	Copyright © since 2010 by CPG-Nuke Dev Team
	http://dragonflycms.org

	Dragonfly is released under the terms and conditions
	of the GNU GPL version 2 or any later version

	$Source$
	$Revision$
	$Author$
	$Date$
**********************************************/

class Poodle_HTTP_Request_CURL extends Poodle_HTTP_Request
{
	public static $VERIFY_HOST = false;

	function __construct($result_class=null)
	{
		parent::__construct($result_class);
		$this->reset();
	}

	public function supportsSSL()
	{
		$v = curl_version();
		if (is_array($v)) {
			return in_array('https', $v['protocols']);
		}
		return is_string($v) ? !!preg_match('/OpenSSL/i', $v) : false;
	}

	public function get($request_url, $extra_headers = null)
	{
		return $this->doRequest($request_url, $extra_headers);
	}

	public function post($request_url, $body, $extra_headers = null)
	{
		return $this->doRequest($request_url, $extra_headers, $body);
	}

	protected function doRequest($request_url, $extra_headers = null, $body = null)
	{
		$url   = $request_url;
		$etime = time() + $this->timeout;
		$redir = true;
		if (is_array($body)) { $body = http_build_query($body); }
		do
		{
			$this->reset();

			if (!$this->canFetchURI($url)) {
				return null;
			}

			if (!$this->allowedURI($url)) {
				trigger_error("Fetching URL not allowed: $url");
				return null;
			}

			$c = curl_init();
			if (false === $c) {
				trigger_error("Could not initialize CURL for URL '$url'");
				return null;
			}

			$cv = curl_version();
			curl_setopt($c, CURLOPT_USERAGENT, $this->user_agent.' '.(is_array($cv) ? 'curl/'.$cv['version'] : $cv));
			curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout);
			curl_setopt($c, CURLOPT_URL, $url);
			curl_setopt($c, CURLOPT_HEADERFUNCTION,array($this, 'fetchHeader'));
			curl_setopt($c, CURLOPT_WRITEFUNCTION, array($this, 'fetchData'));
			if (defined('CURLOPT_NOSIGNAL')) {
				curl_setopt($c, CURLOPT_NOSIGNAL, true);
			}
			if (self::$VERIFY_HOST) {
				curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
				curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
			}
			if ($extra_headers) {
				curl_setopt($c, CURLOPT_HTTPHEADER, $extra_headers);
			}
			if (!is_null($body)) {
				curl_setopt($c, CURLOPT_POST, true);
				curl_setopt($c, CURLOPT_POSTFIELDS, $body);
			}

			curl_exec($c);

			$code = curl_getinfo($c, CURLINFO_HTTP_CODE);
			if (!$code) {
				trigger_error("Error ".curl_errno($c).": ".curl_error($c)." for {$url}");
				curl_close($c);
				return null;
			}
			curl_close($c);

			// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3
			// In response to a request other than GET or HEAD, the user agent MUST NOT
			// automatically redirect the request unless it can be confirmed by the user
			if (is_null($body) && in_array($code, array(301, 302, 303, 307))) {
				$url = self::findRedirect($this->headers, $url);
			} else {
				$redir = false;
				return new $this->result_class($request_url, $url, $code, self::parseHeaders($this->headers), $this->data);
			}

		} while ($redir && ($etime-time() > 0));

		return null;
	}

	protected function reset()
	{
		$this->headers = array();
		$this->data = '';
	}

	protected function fetchHeader($ch, $header)
	{
		array_push($this->headers, rtrim($header));
		return strlen($header);
	}

	protected function fetchData($ch, $data)
	{
		if (strlen($this->data) > 1024*$this->max_response_kb) {
			return 0;
		} else {
			$this->data .= $data;
			return strlen($data);
		}
	}
}
